/******************************************************************************************/
/* Demo2 de UCOS-II                                                                       */
/*    Programme qui lance 4 taches, chaque tache faisant clignoter un LED                 */
/*    Implique l'utilisation de semaphore, mailbox et messageQueue.                       */
/*    Implique l'utilisation de USART1, mais sans interruption.                           */
/* - Ne pas inclure le Framework INTC, utiliser les appels fourni par BSP.c..             */
/* - Les principaux FRAMEWORK-DRIVER GPIO, USART, ADC, FLASH PM sont deja dispo (include) */
/******************************************************************************************/
#include "includes.h"
#include "gpio.h"
#include "led.h"
#include "usart.h"
#include "print_funcs.h"
#include "delay.h"
#include "spi.h"
#include "dip204.h"
#include "pm.h"
#include "adc.h"

/****************************ADC**********************************************************/
#define EXAMPLE_ADC_LIGHT_CHANNEL           2
#define EXAMPLE_ADC_LIGHT_PIN               AVR32_ADC_AD_2_PIN
#define EXAMPLE_ADC_LIGHT_FUNCTION          AVR32_ADC_AD_2_FUNCTION
#define EXAMPLE_ADC_POTENTIOMETER_CHANNEL   1
#define EXAMPLE_ADC_POTENTIOMETER_PIN       AVR32_ADC_AD_1_PIN
#define EXAMPLE_ADC_POTENTIOMETER_FUNCTION  AVR32_ADC_AD_1_FUNCTION


/**** Reservation du STACK de chaque tache ************************************************/
#define OS_TASK_STK_SIZE 256
OS_STK  Alarm_MsgQ_Stk[OS_TASK_STK_SIZE];
OS_STK  LED_LCD_Stk[OS_TASK_STK_SIZE];
OS_STK  UART_Cmd_RX_Stk[OS_TASK_STK_SIZE];
OS_STK  UART_SendSample_Stk[OS_TASK_STK_SIZE];
OS_STK  ADC_Cmd_Stk[OS_TASK_STK_SIZE];

static  void  Alarm_MsgQ(void *p_arg);
static  void  LED_LCD(void *p_arg);
static  void  UART_Cmd_RX(void *p_arg);
static  void  UART_SendSample(void *p_arg);
static  void  ADC_Cmd(void *p_arg);

OS_EVENT	*ADC;		// Semaphore
OS_EVENT	*Error;		// Semaphore
OS_EVENT 	*Aquis;		// Semaphore
OS_EVENT	*Sema2;		// Semaphore
OS_EVENT	*Sema3;		// Semaphore

OS_EVENT	*protectAqisition;	// Semaphore
OS_EVENT	*protectError;		// Semaphore

OS_EVENT	*Mbox1;		// Semaphore
OS_EVENT	*MsgQ1;		// Mailbox

void  *MyMsgQ[3];		// Ma MessageQueue (FIFO)
void Init_IO_Usager(void);          // Fonction definie localement




/******************************************************************************************/
volatile avr32_adc_t *adc = &AVR32_ADC; // ADC IP registers address

// adc light value
volatile signed short adc_value_light;
// adc light potentionmeter
volatile signed short adc_value_pot;

// variable global pour faire clignoter le led3 du au debordement.
volatile unsigned int flagError = 0x00;

// vairable gobal pour faire clignoter lors de l'acquisition
volatile unsigned int flagAcquisition = 0x00;

// ADC IP registers address for the light
unsigned short adc_channel_light = EXAMPLE_ADC_LIGHT_CHANNEL;
// ADC IP registers address for the potentionmeter
unsigned short adc_channel_pot = EXAMPLE_ADC_POTENTIOMETER_CHANNEL;


/**** Fonction principale main()***********************************************************/
int  main (void)
{
	CPU_IntDis();       /* Descative toute les interrupts pendant l'initialisation  */
	OSInit();           /* Initialise "uC/OS-II, The Real-Time Kernel"              */

	/* Creation de toute les taches...a des priorites differentes (5<prio<28) */
	OSTaskCreate(Alarm_MsgQ, NULL, (OS_STK *)&Alarm_MsgQ_Stk[OS_TASK_STK_SIZE-1], 6);
	OSTaskCreate(LED_LCD, NULL, (OS_STK *)&LED_LCD_Stk[OS_TASK_STK_SIZE-1], 7);
	OSTaskCreate(UART_Cmd_RX, NULL, (OS_STK *)&UART_Cmd_RX_Stk[OS_TASK_STK_SIZE-1], 8);
	OSTaskCreate(UART_SendSample, NULL, (OS_STK *)&UART_SendSample_Stk[OS_TASK_STK_SIZE-1], 9);
	OSTaskCreate(ADC_Cmd, NULL, (OS_STK *)&ADC_Cmd_Stk[OS_TASK_STK_SIZE-1], 10);

	Error 	= OSSemCreate(0);		// Semaphore, initialisation
	ADC     = OSSemCreate(0);		// Semaphore, initialisation
	Sema3   = OSSemCreate(0);		// Semaphore, initialisation
	Aquis   = OSSemCreate(0);		// Semaphore, initialisation


	Mbox1   = OSMboxCreate(NULL);   // MailBox,   initialisation
	MsgQ1   = OSQCreate(MyMsgQ, 3); // MailBox,   initialisation

	OSStart();          /* Demarre le multitasking (Donne le controle au noyau uC/OS-II)  */
	// Le code ici ne sera jamais execute
	return (0);         /* Pour eviter le warnings en GCC, prototype (int main (void))    */
}

/******************************************************************************************/
/* Definition des taches sous UCOS-II                                                     */
/*  - Toutes les taches ont une priorite differente                                       */
/*  - Le scheduler de UCOS-II execute TOUJOURS la tache la plus prioritaire qui est READY.*/
/******************************************************************************************/

/******************************************************************************************/
static  void  Alarm_MsgQ (void *p_arg)
{
	//  OS_CPU_SR  cpu_sr = 0;  /* stockage local requis par macro OS_ENTER/EXIT_CRITICAL */
	(void)p_arg;          // Pour eviter le warnings en GCC
	U8 err;// U8 MsgQDataRX;

	BSP_Init();           // Set le timer et demarre les ISR_TICKS.
	// Doit absolument etre appele par la premiere tache a operer.
	// Attention, desormais on roule a 48MHz et USART a 48/2MHz

	CPU_IntDis();		  // Desactive les IRQ pendant l'initialisation
	Init_IO_Usager();     // Initialisation des differents I/O par l'usager, requis ici car much init (irq table,)dne in BSP_init
	Init_IO_LCD();		  // Initialisation du LCD sur la carte
	Init_IO_ADC();		  // Initialisation de ADC
	CPU_IntEn();		  // Reactive les IRQ

	/*---Fin de l'initialisation----------*/

	while (1) {           // Tache, une boucle infinie.
		OSSemPend(ADC, 0, &err);  // Attend le semaphore
		flagError = 0x01;
	}
}
/******************************************************************************************/
static  void  LED_LCD (void *p_arg) //USART_cmd_RX()
{
	(void) p_arg;

	while (1) {
		LED_Toggle(LED0);

		if(flagAcquisition)
			LED_Toggle(LED1);

		if(flagError)
			LED_Toggle(LED2);

		OSTimeDly(500); // Delai en TICKS (1 TICKS=0.5sec)
	}
}
/******************************************************************************************/
static  void  UART_Cmd_RX (void *p_arg)
{
	(void)p_arg;
	U8 MsgQDataPost;

	while (1){
		MsgQDataPost = (AVR32_USART1.rhr & AVR32_USART_RHR_RXCHR_MASK);

		if(MsgQDataPost == 's'){
			flagAcquisition = 0x01;
		}

		else if (MsgQDataPost == 'x'){
			flagAcquisition = 0x00;
		}

		//delai de 200msec
		OSTimeDly(200);


	}
}
/******************************************************************************************/
static void UART_SendSample(void *p_arg) {
	(void) p_arg;
	U8 err;

	while (1) {
		if (flagAcquisition){
			AVR32_USART1.thr = *((U8 *)OSQPend(MsgQ1, 0, &err));
		}
	}
}
/******************************************************************************************/
static void ADC_Cmd(void *p_arg) {
	(void) p_arg;
	//U8 err;
	U8 MboxDataPost;
	MboxDataPost='3';

	while (1) {
		if(flagAcquisition){
			MboxDataPost = ((adc_get_value(adc, adc_channel_light)) << 1);
			OSMboxPost(Mbox1, &MboxDataPost);
			MboxDataPost = (((adc_get_value(adc, adc_channel_pot)) << 1) | 1);
			OSMboxPost(Mbox1, &MboxDataPost);

			// dois checker comment savoir si le mbox est deborder!

		}
	}
}
/******************************************************************************************/

void Init_IO_Usager(void)
{
	static const gpio_map_t USART_GPIO_MAP =
	{
			{AVR32_USART1_RXD_0_0_PIN, AVR32_USART1_RXD_0_0_FUNCTION},
			{AVR32_USART1_TXD_0_0_PIN, AVR32_USART1_TXD_0_0_FUNCTION}
	};
	// Assigner les pins du GPIO a etre utiliser par le USART1.
	gpio_enable_module(USART_GPIO_MAP,sizeof(USART_GPIO_MAP) / sizeof(USART_GPIO_MAP[0]));

	// Initialise le USART1 en mode seriel RS232, a PBA=48/2MHz.
	init_dbg_rs232(24000000);

	print_dbg("blabla");
}

void Init_IO_LCD(void){
	static const gpio_map_t DIP204_SPI_GPIO_MAP =
	{
			{DIP204_SPI_SCK_PIN,  DIP204_SPI_SCK_FUNCTION },  // SPI Clock.
			{DIP204_SPI_MISO_PIN, DIP204_SPI_MISO_FUNCTION},  // MISO.
			{DIP204_SPI_MOSI_PIN, DIP204_SPI_MOSI_FUNCTION},  // MOSI.
			{DIP204_SPI_NPCS_PIN, DIP204_SPI_NPCS_FUNCTION}   // Chip Select NPCS.
	};

	// Switch the CPU main clock to oscillator 0
	pm_switch_to_osc0(&AVR32_PM, FOSC0, OSC0_STARTUP);

	// add the spi options driver structure for the LCD DIP204
	spi_options_t spiOptions =
	{
			.reg          = DIP204_SPI_NPCS,
			.baudrate     = 1000000,
			.bits         = 8,
			.spck_delay   = 0,
			.trans_delay  = 0,
			.stay_act     = 1,
			.spi_mode     = 0,
			.modfdis      = 1
	};

	// Assign I/Os to SPI
	gpio_enable_module(DIP204_SPI_GPIO_MAP,
			sizeof(DIP204_SPI_GPIO_MAP) / sizeof(DIP204_SPI_GPIO_MAP[0]));

	// Initialize as master
	spi_initMaster(DIP204_SPI, &spiOptions);

	// Set selection mode: variable_ps, pcs_decode, delay
	spi_selectionMode(DIP204_SPI, 0, 0, 0);

	// Enable SPI
	spi_enable(DIP204_SPI);

	// setup chip registers
	spi_setupChipReg(DIP204_SPI, &spiOptions, FOSC0);

	// initialize delay driver
	delay_init( FOSC0 );

	// initialize LCD
	dip204_init(backlight_PWM, TRUE);
}

void Init_IO_ADC(void){/*
	static const gpio_map_t ADC_GPIO_MAP = { { EXAMPLE_ADC_LIGHT_PIN,
			EXAMPLE_ADC_LIGHT_FUNCTION }, { EXAMPLE_ADC_POTENTIOMETER_PIN,
					EXAMPLE_ADC_POTENTIOMETER_FUNCTION } };

	gpio_enable_module(ADC_GPIO_MAP, sizeof(ADC_GPIO_MAP)
			/ sizeof(ADC_GPIO_MAP[0]));
	AVR32_ADC.mr |= 0x1 << AVR32_ADC_MR_PRESCAL_OFFSET;
	adc_configure(adc);



	/* Enable the ADC channels. */
	/*	adc_enable(adc, adc_channel_light);
	adc_enable(adc, adc_channel_pot);
	 */
	//AVR32_ADC.ier = AVR32_ADC_IER_EOC2_MASK;
}


